package util;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.HashMap;

import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;

import run.Modulo;

import dto.ConfigServidorDTO;
import dto.SalidaDTO;


public class CONFIG {
	
	private static CONFIG instance = null;
	
	private static CONFIG getInstance() {
		if (instance == null)
			instance = new CONFIG();
		return instance;
	}
	
	private HashMap<String, Modulo> modulos;
	private String pathArchivos, baseBCP;
	
	public static HashMap<String, Modulo> getModulos() {
		return getInstance().modulos;
	}
	
	public static String getPathArchivos() {
		return getInstance().pathArchivos;
	}
	
	public static String getBaseBCP() {
		return getInstance().baseBCP;
	}
	
	private CONFIG() {
		modulos = new HashMap<String, Modulo>();
		String configFilePath = CONFIG.class.getProtectionDomain().getCodeSource().getLocation().getPath().replace(".jar", ".xml");
		//configFilePath += "LogParser.xml"; //REMOVER
		XMLInputFactory factory = XMLInputFactory.newInstance();
		XMLEventReader eventReader = null;
		FileReader file = null;
		
		try {
			file = new FileReader(configFilePath);
			eventReader = factory.createXMLEventReader(file);
		} catch (FileNotFoundException e) {
			System.out.println("ERROR: Archivo de configuracion no encontrado.");
			System.exit(-1);
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		int type = 0;
		String name = null;
		XMLEvent event = null;
		
		try {
			while (eventReader.hasNext()) {
				event = eventReader.nextEvent();
				type = event.getEventType();
				if (type == XMLStreamConstants.START_ELEMENT) {
					name = event.asStartElement().getName().getLocalPart();
					if (name.equals(PARAMS.XMLFileTitle)) {
						procesaConfig(eventReader);
					}
				}
			}
			eventReader.close();
		} catch (XMLStreamException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private void procesaConfig(XMLEventReader eventReader) throws XMLStreamException {
		int type;
		String name;
		XMLEvent event;
		
		while (eventReader.hasNext()) {
			event = eventReader.nextEvent();
			type = event.getEventType();
			
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLParamsTitle)) {
					procesaXMLParams(eventReader);
				}
				
				if (name.equals(PARAMS.XMLModuloTitle)) {
					procesaModulos(eventReader);
				}	
			}
			
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLFileTitle))
					break;
			}
		}
	}

	private void procesaModulos(XMLEventReader eventReader) throws XMLStreamException {
		
		int type;
		String name;
		XMLEvent event;
		
		while (eventReader.hasNext()) {
			event = eventReader.nextEvent();
			type = event.getEventType();
			
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLModulo)) {
					procesaXMLModulo(eventReader);
				}
			}
			
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLModuloTitle))
					break;
			}
		}
	}

	private void procesaXMLParams(XMLEventReader eventReader) throws XMLStreamException {
		String name;
		XMLEvent event;
		int type;
		
		while (eventReader.hasNext()) {
			event = eventReader.nextEvent();
			type = event.getEventType();
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				
				if (name.equals(PARAMS.XMLParamsPath)){
					event = eventReader.nextEvent();
					pathArchivos = event.asCharacters().getData();
					eventReader.nextEvent();
				}
				if (name.equals(PARAMS.XMLParamsBaseBCP)){
					event = eventReader.nextEvent();
					baseBCP = event.asCharacters().getData();
					eventReader.nextEvent();
				}
			}
			
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				
				if (name.equals(PARAMS.XMLParamsTitle))
					break;
			}
		}
	}

	private void procesaXMLModulo(XMLEventReader eventReader) throws XMLStreamException {
		Modulo dto = new Modulo();
		String name;
		while (eventReader.hasNext()) {
			XMLEvent event = eventReader.nextEvent();
			int type = event.getEventType();
			
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				
				if (name.equals(PARAMS.XMLModuloNombre)) {
					event = eventReader.nextEvent();
					dto.nombre = event.asCharacters().getData();
					eventReader.nextEvent();
				}
				
				if (name.equals(PARAMS.XMLModuloUbicacion)) {
					event = eventReader.nextEvent();
					dto.ubicacion = event.asCharacters().getData();
					eventReader.nextEvent();
				}
				
				if (name.equals(PARAMS.XMLModuloServidor)) {
					ConfigServidorDTO auxServ = procesaServidor(eventReader, dto);
					dto.servidores.put(auxServ.nombre, auxServ);
				}
				
				if (name.equals(PARAMS.XMLServidorSalida)) {
					procesaSalida(eventReader, dto);
				}
			}
			
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLModulo))
					break;
			}
		}
		modulos.put(dto.nombre, dto);
	}

	private ConfigServidorDTO procesaServidor(XMLEventReader eventReader, Modulo dto) throws XMLStreamException {
		XMLEvent event;
		int type;
		String name;
		ConfigServidorDTO auxServ = new ConfigServidorDTO();
		
		while (eventReader.hasNext()) {
			event = eventReader.nextEvent();
			type = event.getEventType();
			
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLServidorNombre)) {
					event = eventReader.nextEvent();
					auxServ.nombre = event.asCharacters().getData();
					eventReader.nextEvent();
				} else if (name.equals(PARAMS.XMLServidorOrigen)) {
					event = eventReader.nextEvent();
					auxServ.pathOrigen = event.asCharacters().getData();
					eventReader.nextEvent();
				} else {
					event = eventReader.nextEvent();
					String aux = event.asCharacters().getData();
					eventReader.nextEvent();
					auxServ.parametros.put(name, aux);
				}
			}
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				if (name.equals(PARAMS.XMLModuloServidor))
					break;
			}
		}
		return auxServ;
	}

	private void procesaSalida(XMLEventReader eventReader, Modulo dto) throws XMLStreamException {
		XMLEvent event;
		int type;
		String name;
		String arch = null, tabla = null;
		
		
		while (eventReader.hasNext()) {
			event = eventReader.nextEvent();
			type = event.getEventType();
			if (type == XMLStreamConstants.START_ELEMENT) {
				name = event.asStartElement().getName().getLocalPart();
				
				if (name.equals(PARAMS.XMLServidorArchivo)) {
					event = eventReader.nextEvent();
					arch = event.asCharacters().getData();
					eventReader.nextEvent();
				}
				
				if (name.equals(PARAMS.XMLServidorTabla)) {
					event = eventReader.nextEvent();
					tabla = event.asCharacters().getData();
					eventReader.nextEvent();
				}
			}
			if (type == XMLStreamConstants.END_ELEMENT) {
				name = event.asEndElement().getName().getLocalPart();
				
				if (name == PARAMS.XMLServidorSalida) {
					dto.salidas.add(new SalidaDTO(arch, tabla));
					break;
				}
			}
		}
	}
}
